//xmgrace class  written by M.Nomura
//commented/modified by Brad De Young

//this class abstracts the commands needed to control xmgrace from a running program


#ifndef __GRACESC_H
#define __GRACESC_H

#include <string>
#include <vector>
#include <grace_np.h>
#include <iostream>

namespace gracesc {
     //default parameter file to load
     const std::string DEFAULTFILE("default.par");
     //default buffer size
     const int GRACEBUFFER=2048;
     
     //this class represents one graph in XMGrace
     class XmgraceGraph{
     private:
      //graph number (0 - N)
	  unsigned int graph_number;
	  unsigned int linemax;
	  bool newline;
	  std::vector<std::vector<double> > data;
     public:
     //constructor creates a graph and makes it visible
	  XmgraceGraph(unsigned int number):graph_number(number),linemax(0),newline(true){
	       GracePrintf("g%d hidden false",graph_number);
	  }
	  //overload of << operator to make writing to a graph easier
	  XmgraceGraph& operator << (const char* command){
	       GracePrintf("with g%d",graph_number);
	       GracePrintf("%s",command);
	       return(*this);
	  }
	  //another overload of << operator
	  XmgraceGraph& operator << (const double& variable){
	       if(newline){
		    data.push_back(std::vector<double>());  
		    data[data.size()-1].push_back(variable);
		    newline=false;
	       }
	       else{
		    data[data.size()-1].push_back(variable);
	       }
	       
	       return(*this);
	  }
	  //function to plot a point on the current graph - added by Brad De Young
	  //setnum - set which to plot the point on
      //x and y - coordinates of the point
	  void Plot(int setnum, float x, float y){
           GracePrintf("g%d.s%d point %f, %f",graph_number, setnum, x, y);
      }
	  //yet another overload of << operator
	  void operator << (void (*func)(XmgraceGraph&)){
	       func(*this);
	  }
	  
	  friend void endl(XmgraceGraph&);
	  //clears and saves a the graph
	  void clear(void){
	       for(unsigned int i=0;i<linemax;i++){
		    GracePrintf("kill g%d.s%d saveall",graph_number,i);
	       }
	       linemax=0;
	  }
	  //draws the graph
	  void draw(void){
	    if ( data.empty() == false ){
	       unsigned int lasttime=data.size();
	       unsigned int lastline=data[0].size();
	       if(lastline>linemax){
		    linemax=lastline;
	       }
	       for(unsigned int i=0;i<lasttime;i++){
		    for(unsigned int j=1;j<lastline;j++){
			 GracePrintf("g%d.s%d point %f,%f",graph_number,j-1,data[i][0],data[i][j]);
		    }
	       }
	       for(unsigned int i=0;i<lasttime;i++){
		    data[i].clear();
	       }
	       data.clear();
	    }
	  }
	  //loads commands from a file
	  void load_commands(const std::string & filename);
	  
     };
     
     //this class represents an instance of the Xmgrace program
     class Xmgrace{
     private:
       //list of graphs in the process
       std::vector<XmgraceGraph> graph;
       int max_graph_size;
       
     public:
	//opens xmgrace and initializes it with parameter file you pass in
	  void init(const std::string & parameter_file = "" ){
	       if ( parameter_file == ""){ // no parameter file 
		    if(GraceOpen(GRACEBUFFER)==-1){
			 std::cerr << "Can't run Grace." << std::endl;
			 exit(-1);
		    }
	       } else {
		    if( GraceOpenVA("xmgrace",GRACEBUFFER , "-nosafe", "-noask","-param", parameter_file.c_str(), NULL) == -1 ){
			 std::cerr << "Can't run Grace.(" << parameter_file << ")" << std::endl;
			 exit(-1);
		    }
	       
	       GracePrintf("focus off");
	}
	  }
      //constructor - size is number of graphs to be created
	Xmgrace():max_graph_size(-1){
		add(1);
	}
	  Xmgrace(unsigned int size=0):max_graph_size(-1){
	       //init();
	       add(size);
	  }
	  //another constructor - size is same as above, parameter_file is file containing a list of parameters to pass to grace on init
	  Xmgrace( const std::string &parameter_file = DEFAULTFILE,unsigned int size=0 ):max_graph_size(-1){
	       init(parameter_file);
	       add(size);
	  }
	  //destructor
	  virtual ~Xmgrace (){GraceClosePipe();}
	  //adds a graph
	  void add(unsigned int size){
	       for(unsigned int i=0;i<size;i++){
		    max_graph_size++;
		    graph.push_back(XmgraceGraph(max_graph_size));
	       }
	  }
	  //send a comand to grace
	  Xmgrace& operator << (const char* command){
	       GracePrintf("%s",command);
	       return(*this);
	  }
	  //get a certain graph out of grace
	  XmgraceGraph& operator [] (unsigned int number){
	       return graph[number];
	  }
	  //returns if grace is open
	  bool open(void){
	       return GraceIsOpen();
	  }
	  //load commands from a file
	  void load_commands(const std::string & filename);
	  //redraw all the graphs
	  void redraw(void){
	       GracePrintf("redraw");
	  }

     };
     
     void endl(XmgraceGraph&);
     
}

#endif
